package gang.org.springframework.framework.beanfactorypostprocessor;

import gang.org.springframework.framework.annotation.GangConfigurationClass;
import gang.org.springframework.framework.annotation.GangConfigurationClassBeanDefinitionReader;
import gang.org.springframework.framework.annotation.GangConfigurationClassParser;
import gang.org.springframework.framework.annotation.GangConfigurationClassUtils;
import gang.org.springframework.framework.bean.GangAbstractBeanDefinition;
import gang.org.springframework.framework.bean.GangBeanDefinition;
import gang.org.springframework.framework.bean.GangBeanDefinitionHolder;
import gang.org.springframework.framework.context.GangResourceLoaderAware;
import gang.org.springframework.framework.core.type.classreading.GangCachingMetadataReaderFactory;
import gang.org.springframework.framework.core.type.classreading.GangMetadataReaderFactory;
import gang.org.springframework.framework.factory.GangConfigurableListableBeanFactory;
import gang.org.springframework.framework.factory.parsing.GangPassThroughSourceExtractor;
import gang.org.springframework.framework.factory.parsing.GangSourceExtractor;
import gang.org.springframework.framework.io.GangDefaultResourceLoader;
import gang.org.springframework.framework.io.GangResourceLoader;
import gang.org.springframework.framework.support.GangAnnotationBeanNameGenerator;
import gang.org.springframework.framework.support.GangBeanDefinitionRegistry;
import gang.org.springframework.framework.support.GangBeanNameGenerator;
import gang.org.springframework.framework.support.GangFullyQualifiedAnnotationBeanNameGenerator;
import gang.org.springframework.framework.util.GangClassUtils;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * @author gang.chen
 * 业务意义
 *      1> 自动配置的入口
 *      2> 获取所有的 BeanDefinition并存入到 List<GangBeanDefinitionHolder>
 *      3> 提供解析 SpringbootManualApplication入口
 * @Date 2021/6/14 21:08
 */
public class GangConfigurationClassPostProcessor implements GangBeanDefinitionRegistryPostProcessor, GangResourceLoaderAware {

    public static final GangAnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR = GangFullyQualifiedAnnotationBeanNameGenerator.INSTANCE;

    private GangBeanNameGenerator importBeanNameGenerator = IMPORT_BEAN_NAME_GENERATOR;

    private GangConfigurationClassBeanDefinitionReader reader;

    private GangMetadataReaderFactory metadataReaderFactory = new GangCachingMetadataReaderFactory();

    private ClassLoader beanClassLoader = GangClassUtils.getDefaultClassLoader();

    private GangSourceExtractor sourceExtractor = new GangPassThroughSourceExtractor();

    private GangBeanNameGenerator componentScanBeanNameGenerator = GangAnnotationBeanNameGenerator.INSTANCE;

    private GangResourceLoader resourceLoader = new GangDefaultResourceLoader();

    /**
     * @param registry {@link gang.org.springframework.framework.factory.GangDefaultListableBeanFactory}
     * */
    @Override
    public void postProcessBeanDefinitionRegistry(GangBeanDefinitionRegistry registry)
    {
        processConfigBeanDefinitions(registry);
    }

    @Override
    public void postProcessBeanFactory(GangConfigurableListableBeanFactory beanFactory)
    {
        //TODO
        enhanceConfigurationClasses(beanFactory);
    }

    /**
     * 业务意义
     * 1，GangAbstractBeanDefinition属性beanClass，由spring.factories加载后是一个类路径
     * 2，beanClass值，由String转为Class对象
     * */
    private void enhanceConfigurationClasses(GangConfigurableListableBeanFactory beanFactory) {
        //TODO
        for (String name : beanFactory.getBeanDefinitionNames()) {
            GangBeanDefinition beanDef = beanFactory.getBeanDefinition(name);

            //TODO
            if (beanDef instanceof GangAbstractBeanDefinition) {

                GangAbstractBeanDefinition abd = (GangAbstractBeanDefinition) beanDef;

                if(!abd.hasBeanClass()){
                    abd.resolveBeanClass(this.beanClassLoader);
                }
            }
        }
    }



    /**
     * @param registry {@link gang.org.springframework.framework.factory.GangDefaultListableBeanFactory}
     * */
    public void processConfigBeanDefinitions(GangBeanDefinitionRegistry registry)
    {
        List<GangBeanDefinitionHolder> beanDefinitionHolders = new ArrayList<>();

        /**
         * TODO
         * 1）上下文中有多个BeanDefinitionNames
         * 2）只获取项目启动主类SpringbootManualApplication被封装的BeanDefinition
         * */
        String[] candidateNames = registry.getBeanDefinitionNames();
        for (String beanName : candidateNames) {
            GangBeanDefinition beanDef = registry.getBeanDefinition(beanName);
            if (GangConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,null)) {
                beanDefinitionHolders.add(new GangBeanDefinitionHolder(beanDef,beanName));
            }
        }

        /**
         * TODO
         * GangConfigurationClassParser 作为一个解析类的主类
         * */
        GangConfigurationClassParser parser = new GangConfigurationClassParser(
                this.metadataReaderFactory,
                null,
                null,
                this.resourceLoader,
                this.componentScanBeanNameGenerator,
                registry
        );

        /*
         * TODO
         * Set<GangBeanDefinitionHolder> GangBeanDefinitionHolder集合是对项目启动主类（SpringbootManualApplication）的封装
         * */
        Set<GangBeanDefinitionHolder> candidates = new LinkedHashSet<>(beanDefinitionHolders);

        do {
            /*
             * TODO
             * 业务意义
             * 1，解析项目启动类SpringbootManualApplication.class -> GangBeanDefinitionHolder.class
             * 2，为解析启动类提现一个解析器GangConfigurationClassParser
             * */
            parser.parse(candidates);

            /*
             * TODO 将spring.factories自动配置类字符转为BeanDefinition
             * 业务意义
             * 1）解析类：GangConfigurationClassParser
             * 2）解析获取的结果：Map<GangConfigurationClass,GangConfigurationClass>
             * */
            Set<GangConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            if(this.reader == null){
                /*
                 * 业务意义
                 * 1）GangConfigurableListableBeanFactory（工厂类）强转->GangBeanDefinitionRegistry 实现将Class转为BeanDefinition存到缓存中
                 * 2）初始化GangConfigurationClassBeanDefinitionReader时，初始化registry
                 * */
                this.reader = new GangConfigurationClassBeanDefinitionReader(registry,
                        sourceExtractor,
                        null,
                       null,
                        this.importBeanNameGenerator,
                        null);
            }

            /*
             * GangConfigurationClass对象的理解
             * 1）GangConfigurationClass是对工厂类的定义，例如工厂内部类：GangEnableWebmvcConfiguration
             *
             * GangBeanMethod 对象的理解
             * 2）GangBeanMethod 是对工厂类的方法的定义，例如 public GangResourceUrlProvider mvcResourceUrlProvider(){}
             *
             * GangConfigurationClass是对一个类和类方法的描述
             * */
            this.reader.loadBeanDefinitions(configClasses);

            candidates.clear();
        }
        while (!candidates.isEmpty());
    }

    @Override
    public void setResourceLoader(GangResourceLoader resourceLoader) {

        this.resourceLoader = resourceLoader;
    }

}
